package com.central.apps.service.impl;

import com.central.app.service.HandlerService;
import com.central.apps.common.constant.BizConstant;
import com.central.apps.service.BudgetService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 预算接口实现类
 *
 * @author 李大超
 * @date 2023/3/27
 */
@Slf4j
@Service
public class BudgetServiceImpl implements BudgetService {
    @Autowired
    private HandlerService handlerService;

    @Override
    public void updateBudgetInfo(Integer proId, Integer pbdId, BigDecimal usedAmt) throws Exception {
        if (usedAmt == null || usedAmt.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }

        // 查询课题号
        Map<String, Object> proMap = handlerService.findOneBySql("select subjectno from gq_proaccount where id = " + proId);
        String subjectNo = MapUtils.getString(proMap, "subjectno");

        if (BizConstant.PUBLIC_SUBJECT_NO.equals(subjectNo)) {
            // 处理公共年度预算
            dealPublicBudget(proId, pbdId, usedAmt);
        } else {
            // 处理年度预算
            dealBudget(proId, pbdId, usedAmt);
        }
    }

    @Override
    public void budgetOccupyRelease(Integer proId, Integer pbiId, BigDecimal applyAmt, boolean flag) throws Exception {
        if (applyAmt == null || applyAmt.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }

        // 查询年度预算执行中的预算项
        Map<String, Object> map = handlerService.findOneBySql("select * from gq_probudget where status = '执行中' and id = " + pbiId + " and proid = " + proId);

        if (map != null && !map.isEmpty()) {
            // 父预算项id
            Integer pbiParentId = MapUtils.getInteger(map, "pbiparentid");

            StringBuilder sb = new StringBuilder();
            sb.append("update gq_probudget set ");
            if (flag) {
                sb.append("usefulamt = usefulamt - ").append(applyAmt);
                sb.append(", occupyamt = occupyamt + ").append(applyAmt);
            } else {
                sb.append("usefulamt = usefulamt + ").append(applyAmt);
                sb.append(", occupyamt = occupyamt - ").append(applyAmt);
            }
            sb.append(" where id = ").append(MapUtils.getInteger(map, "id"));

            // 更新成本占用
            handlerService.updateBySql(sb.toString());

            if (pbiParentId > 0) {
                String year = MapUtils.getString(map, "year");
                map = handlerService.findOneBySql("select id from gq_probudget where status = '执行中' and pbiid = " + pbiParentId + " and proid = " + proId + " and year = '" + year + "'");

                if (map != null && !map.isEmpty()) {
                    // 递归更新父级预算项金额明细信息
                    budgetOccupyRelease(proId, MapUtils.getInteger(map, "id"), applyAmt, flag);
                }
            }
        }
    }

    @Override
    public String judgeBeyondBudget(Integer proId, List<Map<String, Object>> data) throws Exception {
        // 查询课题号
        Map<String, Object> proMap = handlerService.findOneBySql("select subjectno from gq_proaccount where id = " + proId);
        String subjectNo = MapUtils.getString(proMap, "subjectno");

        if (BizConstant.PUBLIC_SUBJECT_NO.equals(subjectNo)) {
            // 处理公共年度预算
            return judgePublicBudget(proId, data);
        } else {
            // 处理年度预算
            return judgeBudget(proId, data);
        }
    }

    @Override
    public void updateBudgetApplyAmt(Integer proId, List<Map<String, Object>> data) throws Exception {
        // 查询项目概算信息
        List<Map<String, Object>> list = handlerService.findBySql("select id, pbiid, applyamt from gq_pblbestimate where proid = " + proId);

        // 更新项目概算申请和可用金额
        for (Map<String, Object> dataMap : data) {
            for (Map<String, Object> map : list) {
                if (dataMap.get("pbiid").equals(map.get("pbiid"))) {
                    Integer id = MapUtils.getInteger(map, "id");
                    String budgetAmt = MapUtils.getString(dataMap, "budgetamt");
                    BigDecimal budgetAmtDec = new BigDecimal(budgetAmt);

                    handlerService.updateBySql("update gq_pblbestimate set applyamt = applyamt + " + budgetAmtDec +
                            ", usefulamt = usefulamt - " + budgetAmtDec + " where id = " + id);
                    break;
                }
            }
        }
    }

    /**
     * 判断年度预算是否超支
     *
     * @param proId
     * @param data
     * @return
     */
    private String judgePublicBudget(Integer proId, List<Map<String, Object>> data) {
        // 查询预算基线信息
        List<Map<String, Object>> list = handlerService.findBySql("select pbiid, budgetitem, usefulamt from gq_ppbudget where proid = " + proId);

        StringBuilder sb = new StringBuilder();
        for (Map<String, Object> dataMap : data) {
            for (Map<String, Object> map : list) {
                if (dataMap.get("pbiid").equals(map.get("pbiid"))) {
                    String budgetAmt = MapUtils.getString(dataMap, "budgetamt");
                    if (StringUtils.isEmpty(budgetAmt)) {
                        continue;
                    }
                    BigDecimal budgetAmtDec = new BigDecimal(budgetAmt);
                    String usefulAmt = MapUtils.getString(map, "usefulamt");
                    BigDecimal usefulAmtDec = new BigDecimal(usefulAmt);

                    if (budgetAmtDec.compareTo(usefulAmtDec) > 0) {
                        sb.append(MapUtils.getString(map, "budgetitem")).append("、");
                    }

                    break;
                }
            }
        }

        if (StringUtils.isNotEmpty(sb.toString())) {
            sb.deleteCharAt(sb.length() - 1);
            sb.append("等预算项超出公共预算年度预算金额, 请重新进行编制!");

            return sb.toString();
        }

        return null;
    }

    /**
     * 判断公共年度预算是否超支
     *
     * @param proId
     * @param data
     * @return
     */
    private String judgeBudget(Integer proId, List<Map<String, Object>> data) {
        // 查询预算基线信息
        List<Map<String, Object>> list = handlerService.findBySql("select pbiid, budgetitem, usefulamt from gq_pblbestimate where proid = " + proId);

        StringBuilder sb = new StringBuilder();
        for (Map<String, Object> dataMap : data) {
            for (Map<String, Object> map : list) {
                if (dataMap.get("pbiid").equals(map.get("pbiid"))) {
                    String budgetAmt = MapUtils.getString(dataMap, "budgetamt");
                    if (StringUtils.isEmpty(budgetAmt)) {
                        continue;
                    }
                    BigDecimal budgetAmtDec = new BigDecimal(budgetAmt);
                    String usefulAmt = MapUtils.getString(map, "usefulamt");
                    BigDecimal usefulAmtDec = new BigDecimal(usefulAmt);

                    if (budgetAmtDec.compareTo(usefulAmtDec) > 0) {
                        sb.append(MapUtils.getString(map, "budgetitem")).append("、");
                    }

                    break;
                }
            }
        }

        if (StringUtils.isNotEmpty(sb.toString())) {
            sb.deleteCharAt(sb.length() - 1);
            sb.append("等预算项超出项目概算, 请重新进行编制!");

            return sb.toString();
        }

        return null;
    }

    /**
     * 处理年度预算
     *
     * @param proId
     * @param pbdId
     * @param usedAmt
     */
    private void dealBudget(Integer proId, Integer pbdId, BigDecimal usedAmt) throws Exception {
        // 查询年度预算执行中的预算项
        Map<String, Object> map = handlerService.findOneBySql("select * from gq_probudget where status = '执行中' and id = " + pbdId + " and proid = " + proId);

        if (map != null && !map.isEmpty()) {
            // 预算项id
            Integer pbiId = MapUtils.getInteger(map, "pbiid");
            // 父预算项id
            Integer pbiParentId = MapUtils.getInteger(map, "pbiparentid");

            // 计算预算各项属性值
            String budgetamt = MapUtils.getString(map, "budgetamt");
            BigDecimal budgetamtDec = new BigDecimal(budgetamt);
            String occupyAmt = MapUtils.getString(map, "occupyamt");
            BigDecimal occupyAmtDec = new BigDecimal(occupyAmt);

            String actualAmt = MapUtils.getString(map, "actualamt");
            BigDecimal actualAmtDec = new BigDecimal(actualAmt);
            BigDecimal actualamtRes = actualAmtDec.add(usedAmt);

            BigDecimal finishPercent;
            BigDecimal differenceAmt = BigDecimal.ZERO;
            if (actualamtRes.compareTo(budgetamtDec) >= 0) {
                finishPercent = BigDecimal.valueOf(100);
                differenceAmt = actualamtRes.subtract(budgetamtDec);
            } else {
                finishPercent = actualamtRes.divide(budgetamtDec, 6, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            }

            if (actualamtRes.compareTo(occupyAmtDec) > 0) {
                occupyAmtDec = BigDecimal.ZERO;
            } else {
                occupyAmtDec = occupyAmtDec.subtract(usedAmt);
            }

            BigDecimal usefulAmt = budgetamtDec.subtract(occupyAmtDec).subtract(actualamtRes);

            // 组织更新信息
            Map<String, Object> updMap = new HashMap<>(5);
            updMap.put("id", map.get("id"));
            updMap.put("actualamt", actualamtRes);
            updMap.put("finishpercent", finishPercent);
            updMap.put("differenceamt", differenceAmt);
            updMap.put("occupyamt", occupyAmtDec);
            updMap.put("usefulamt", usefulAmt);

            // 更新预算项信息
            handlerService.update("gq_probudget", updMap);

            if (pbiParentId > 0) {
                String year = MapUtils.getString(map, "year");
                map = handlerService.findOneBySql("select id from gq_probudget where status = '执行中' and pbiid = " + pbiParentId + " and proid = " + proId + " and year = '" + year + "'");

                if (map != null && !map.isEmpty()) {
                    // 递归更新父级预算项金额明细信息
                    updateBudgetInfo(proId, MapUtils.getInteger(map, "id"), usedAmt);
                }
            }

            // 更新项目概算实际发生金额
            handlerService.updateBySql("update gq_pblbestimate set actualamt = actualamt + " + actualamtRes +
                    ", usefulamt = budgetamt - applyamt - surplusamt where proid = " + proId + " and pbiid = " + pbiId);
        }
    }

    /**
     * 处理公共年度预算
     *
     * @param proId
     * @param pbdId
     * @param usedAmt
     */
    private void dealPublicBudget(Integer proId, Integer pbdId, BigDecimal usedAmt) throws Exception {
        // 查询年度预算执行中的预算项
        Map<String, Object> map = handlerService.findOneBySql("select * from gq_ppbudget where status = '执行中' and id = " + pbdId + " and proid = " + proId);

        if (map != null && !map.isEmpty()) {
            // 父预算项id
            Integer pbiParentId = MapUtils.getInteger(map, "pbiparentid");

            // 计算预算各项属性值
            String budgetamt = MapUtils.getString(map, "budgetamt");
            BigDecimal budgetamtDec = new BigDecimal(budgetamt);

            String actualAmt = MapUtils.getString(map, "actualamt");
            BigDecimal actualAmtDec = new BigDecimal(actualAmt);
            BigDecimal actualamtRes = actualAmtDec.add(usedAmt);

            BigDecimal finishPercent;
            BigDecimal differenceAmt = BigDecimal.ZERO;
            if (actualamtRes.compareTo(budgetamtDec) >= 0) {
                finishPercent = BigDecimal.valueOf(100);
                differenceAmt = actualamtRes.subtract(budgetamtDec);
            } else {
                finishPercent = actualamtRes.divide(budgetamtDec, 6, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            }

            BigDecimal usefulAmt = budgetamtDec.subtract(actualamtRes);

            // 组织更新信息
            Map<String, Object> updMap = new HashMap<>(5);
            updMap.put("id", map.get("id"));
            updMap.put("actualamt", actualamtRes);
            updMap.put("finishpercent", finishPercent);
            updMap.put("differenceamt", differenceAmt);
            updMap.put("usefulamt", usefulAmt);

            // 更新预算项信息
            handlerService.update("gq_ppbudget", updMap);

            if (pbiParentId > 0) {
                String year = MapUtils.getString(map, "year");
                map = handlerService.findOneBySql("select id from gq_ppbudget where status = '执行中' and pbiid = " + pbiParentId + " and proid = " + proId + " and year = '" + year + "'");

                if (map != null && !map.isEmpty()) {
                    // 递归更新父级预算项金额明细信息
                    updateBudgetInfo(proId, MapUtils.getInteger(map, "id"), usedAmt);
                }
            }
        }
    }
}
